/*
  maptalks地图区域面绘制，及撒点，及热力图测试
*/

<template>
  <div
    id="map"
    class="container"
  />
</template>
<script>
import 'maptalks/dist/maptalks.css'
import * as maptalks from 'maptalks'
import { HeatLayer } from 'maptalks.heatmap'

const simingAreaData = require('@/static/xiamenSiming.js')
const geoJson = require('@/static/xiamen.json')

export default {
  name: 'MapCustom',
  data () {
    return {
      // 地图引擎
      mapEngine: null,
      map: this,
      center: [118.13245430046891, 24.495713873147764],
      urlTemplate: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
      subdomains: ['a', 'b', 'c', 'd'],
      attribution: null,
      // 倾斜度
      pitch: 50,
      // toolbar
      // 旋转
      whirl: null,
      // 放大/缩小
      zoom: 14,
      // 轴承
      bearing: 0,
      // 屏幕坐标
      containerPoint: { x: null, y: null },
      // 地图坐标
      coordinatePoint: { x: null, y: null },
      geoJson: geoJson
    }
  },
  mounted () {
    const _t = this
    this.$nextTick(() => {
      _t.mapEngine = _t.initMap()

      // 创建图层
      // new maptalks.VectorLayer('v').addTo(_t.mapEngine)

      // 锁定视角
      _t.lockView()

      // 创建工具栏
      _t.addToolbar()

      // 增加缩放工具
      _t.addZoomTool()

      // 画区域面
      // _t.drawArea()

      _t.addHeatLayer()

      // 增加事件，监听获取到鼠标点击的坐标
      _t.mapEngine.on('click', function (e) {
        _t.containerPoint = e.containerPoint
        _t.coordinatePoint = _t.mapEngine.containerPointToCoordinate(e.containerPoint)
        console.log('屏幕坐标：' + JSON.stringify(_t.containerPoint))
        console.log('地图坐标：' + JSON.stringify(_t.coordinatePoint))
      })
    })
  },

  methods: {

    /**
             * 初始化地图
             */
    initMap () {
      const _t = this
      return new maptalks.Map('map', {
        // 默认中心点点位
        center: _t.center,
        // 缩放层级
        zoom: _t.zoom,
        // 倾斜度
        pitch: _t.pitch,
        // 最小缩放层级
        minZoom: 1,
        // 最大缩放层级
        maxZoom: 18,
        baseLayer: new maptalks.TileLayer('base', {
          // 电子地图图层
          urlTemplate: _t.urlTemplate,
          subdomains: _t.subdomains,
          attribution: _t.attribution
        })
      })
    },

    /**
             * 限制地图区域
             */
    lockView () {
      const extent = this.mapEngine.getExtent()
      this.mapEngine.setMaxExtent(extent)
    },

    /**
             * 添加图层
             */
    addLayer () {
      return new maptalks.VectorLayer('v').addTo(this.mapEngine)
    },

    /**
             * 创建工具栏
             */
    addToolbar () {
      const _t = this
      const map = this.mapEngine
      new maptalks.control.Toolbar({
        items: [
          {
            item: '放大',
            click: () => {
              map.setZoom(_t.zoom += 1)
            }
          },
          {
            item: '缩小',
            click: () => {
              map.setZoom(_t.zoom -= 1)
            }
          },
          {
            item: '旋转',
            click: () => {
              map.setBearing(_t.bearing -= 50)
            }
          },
          {
            item: '重置',
            click: () => {
              _t.mapDataReset(map)
            }
          },
          {
            item: '锁定',
            click: (t) => {
              if (t.target.item === '锁定') {
                map.setOptions({
                  // 可拖动
                  draggable: false,
                  // 平移
                  dragPan: false,
                  // 旋转
                  dragRotate: false,
                  // 间距
                  dragPitch: false,
                  // 滚动缩放
                  scrollWheelZoom: false,
                  // 点击 缩放
                  touchZoom: false,
                  // 双击缩放
                  doubleClickZoom: false
                })
                t.target.item = '取消锁定'
              } else {
                map.setOptions({
                  // 可拖动
                  draggable: true,
                  // 平移
                  dragPan: true,
                  // 旋转
                  dragRotate: true,
                  // 间距
                  dragPitch: true,
                  // 滚动缩放
                  scrollWheelZoom: true,
                  // 点击 缩放
                  touchZoom: true,
                  // 双击缩放
                  doubleClickZoom: true
                })
                t.target.item = '锁定'
              }
            }
          }
        ]
      }).addTo(map)
    },

    /**
             * 增加缩放工具
             */
    addZoomTool () {
      new maptalks.control.Zoom({
        // 工具位置
        position: 'top-left',
        // 是否是以线段条方式展示
        slider: false,
        // 是否显示缩放级别文本框
        zoomLevel: true
      }).addTo(this.mapEngine)
    },

    /**
             * 地图数据重置
             */
    mapDataReset () {
      this.pitch = 50
      this.bearing = 0
      this.zoom = 14
      this.mapEngine.setPitch(this.pitch)
      this.mapEngine.setBearing(this.bearing)
      this.mapEngine.setZoom(this.zoom)
    },

    /**
             * 再图层上画面
             */
    drawArea () {
      const _t = this
      const layer = _t.mapEngine.getLayer('v')
      _t.drawAreaPolygon(_t.geoJson, layer)
      layer.setOptions({
        // 启用高度绘制
        enableAltitude: true,
        altitudeProperty: 'altitude',
        // 绘制高度线
        drawAltitude: {
          lineWidth: 1,
          lineColor: '#000'
        }
      })
    },

    /**
             * 根据geojson画区域面
             * @param geoJson geoJson数据
             * @param layer 需要话的图层
             */
    drawAreaPolygon (geoJson, layer) {
      const geometry = maptalks.GeoJSON.toGeometry(geoJson)

      const centerCoordinates = []
      if (geometry) {
        geometry.forEach(g => {
          g.setSymbol({
            // 线色
            lineColor: '#34495e',
            // 线宽
            lineWidth: 1,
            // 填充色
            polygonFill: 'rgb(135,196,240)',
            // 不透明度
            polygonOpacity: 0.2
          })
          // 设置信息框
          g.setInfoWindow({
            title: g.properties.name,
            content: '<br style="color:#f00">中心点：' + g.properties.center + ' </br>行政区划：' + g.properties.adcode + ' </br>父级行政区划：' + g.properties.parent.adcode + '</div>'
          })
          g.setMenu({
            width: 160,
            custom: false,
            items: [
              { item: '菜单一', click: function () { alert('Query Clicked!'); return false } },
              '-',
              { item: '菜单二', click: function () { alert('Edit Clicked!') } },
              { item: '菜单三', click: function () { alert('About Clicked!') } }
            ]
          })
          // 鼠标交互事件监听
          g.on('mouseenter', function (e) {
            e.target.updateSymbol({
              polygonFill: '#f00'
            })
          }).on('mouseout', function (e) {
            e.target.updateSymbol({
              polygonFill: 'rgb(135,196,240)'
            })
          }).on('click', function (e) {
            e.target.openInfoWindow(e.coordinate)
          })

          // 获取中心坐标
          centerCoordinates.push(g.properties)
        })
      }
      layer.addGeometry(geometry)

      this.drawMark(centerCoordinates, layer)
    },

    drawMark (centerPointList, layer) {
      if (!centerPointList) {
        console.log('无区域中心点数据')
        return
      }
      const info = { content: '', width: 150, minHeight: 100 }
      const result = []
      // 这里 d 的数据格式是数组，如：[-0.113049, 51.498568]
      centerPointList.forEach(d => {
        if (!d.info) {
          d.info = info
        }
        // 设有高度、高亮的mark
        const mark = new maptalks.Marker(d.center, {
          // 设置了这个属性，会替换默认的图标
          // symbol: {
          // markerFile: 'foo.png',
          // textName: d.name
          // },
          properties: {
            // 高度设置
            altitude: 50
          }
        }).addTo(layer)
        mark.setInfoWindow({
          title: d.name,
          content: '<div>' + d.adcode + '</div>',
          // autoPan: true,
          width: d.info.width,
          minHeight: d.info.minHeight
          // 'custom': false,
          // 点击打开和关闭
          // autoOpenOn: 'click',
          // autoCloseOn: 'click'
        })

        // 没有高度的mark
        // new maptalks.Marker(d).updateSymbol({
        //   markerOpacity: 0.5,
        //   markerFill: '#bbb'
        // }).addTo(layer)

        mark.setZIndex(1000)
        result.push(mark)
      })
      return result
    },

    addHeatLayer () {
      const h1 = []
      for (let i = 0; i < simingAreaData.simingAreaData.length; i++) {
        const s = simingAreaData.simingAreaData[i]
        s.pointList.forEach(ss => {
          ss.forEach(sss => {
            sss.push(i + '100')
            h1.push(sss)
          })
        })
      }
      // 创建图层
      const hl = new HeatLayer('heat', h1, {
        // 热力比例（我的理解是，在0-1之间，也就是0-100%，一个热力点，的热力程度是多少
        heatValueScale: 0.7,
        // 旋转时强制刷新
        forceRenderOnRotating: true,
        // 移动时强制刷新
        forceRenderOnMoving: true
        // 模糊因子, 值越大,越平滑,默认值是15
        // blur: 20,
        // 每个数据点的半径(默认值25，也建议25，我建议不能小于20）
        // radius: 25,
        // 最小不透明读，越小越透明
        // minOpacity: 0.8,
        // 热力梯度，是热力点外围的颜色值，从外围到里，值是递增的，最大值就是中心的位置
        // gradient: {
        //   0.4: 'blue',
        //   0.6: 'cyan',
        //   0.7: 'lime',
        //   0.8: 'yellow',
        //   1.0: 'red'
        // }
      })
      hl.addTo(this.mapEngine)
      this.drawLine()
    },
    drawLine () {
      // 热力图，本身是对点进行扩散渲染的，而且并没有开发出可交互的接口（我暂时还没找到），所以只能找替代方法，

      // 方法一
      // canvas绘制point，和热力图重合，并添加监听事件，也可以绘制mark，不过它们之间的性能需要分析下
      // 这个方法可以单独对点做弹窗
      const h1 = []
      for (let i = 0; i < simingAreaData.simingAreaData.length; i++) {
        simingAreaData.simingAreaData[i].pointList[0].forEach(d => {
          h1.push(d)
        })
      }
      var mPoint = new maptalks.MultiPoint(h1, {
        visible: true,
        // 可交互
        interactive: true,
        cursor: 'pointer',
        // 可拖拽
        draggable: false,
        zIndex: 10,
        symbol: {
          // 不透明度，这里不设置0是因为，值为0交互会失效
          markerOpacity: 0.1,
          markerFillOpacity: 0.1,
          markerLineOpacity: 0,
          // 填充色，使用热力图相近的颜色
          markerFill: 'red',
          markerType: 'ellipse',
          // 这里保持和热力图（对应heatMap的radiu，而且要大一点，这里我是比热力图的大10）
          markerWidth: 35,
          markerHeight: 35
        }
      })
      mPoint.on('mousemove', function (e) {
        e.target.openInfoWindow(e.coordinate)
      }).on('mouseout', function (e) {
        e.target.closeInfoWindow()
      }).setInfoWindow({
        content: 'hello world',
        title: 'message',
        animationDuration: 0,
        autoOpenOn: false
      })
      new maptalks.VectorLayer('pointLayer', mPoint).addTo(this.mapEngine)

      // 方法二
      // 用其他可交互图形替代，使用几何图形，这个要求是对真个热力图都是一样的弹窗，将整个热力图作为一个整体
      // 这里我用的几何图形，有太多限制，不太符合要求，但可以作为一个思路参考，
      const geometry = maptalks.GeoJSON.toGeometry(simingAreaData.geoData)
      if (geometry) {
        geometry.forEach(g => {
          g.setSymbol({
            // 线色
            lineColor: '#f298bc',
            // 线宽
            // 这里保持和热力图（对应heatMap的radiu，而且要大一点）
            lineWidth: 30,
            // 不透明度
            polygonOpacity: 0,
            // 圆角设置
            lineJoin: 'round'
          })
          g.on('mousemove', function (e) {
            e.target.openInfoWindow(e.coordinate)
          }).on('mouseout', function (e) {
            e.target.closeInfoWindow()
          }).setInfoWindow({
            content: 'hello world',
            title: 'message',
            animationDuration: 0,
            autoOpenOn: false
          })
        })
      }
      const options = {
        enableAltitude: true,
        zIndex: 10
      }
      // new maptalks.VectorLayer('lineLayer', options).addGeometry(geometry).addTo(this.mapEngine)

    }

  }
}
</script>

<style scoped lang="scss">
  html, body {
    margin: 0px;
    height: 100%;
    width: 100%;
  }

  .container {
    width: 100%;
    height: 100%
  }
</style>
